import 'dart:async';

import 'package:dio/dio.dart';

import '../../controller/event/loading_event.dart';
import '../../env.dart';
import '../alert.dart';
import '../router/log_util.dart';
import '../router/router_util.dart';

class NetUtils {
  static const NET_SUCCESS = '0000'; // 接口交互成功
  final LoadingInterceptors _loadingInterceptors = LoadingInterceptors();

  /// 超时监听
  final ErrorInterceptors _errorInterceptors = ErrorInterceptors();

  final HeaderInterceptors _headerInterceptors = HeaderInterceptors();

  NetUtils();

  ///获取通用Dio操作对象
  Dio getDio(bool showLoading, bool showErrorToast, {bool loginCheck = true}) {
    var _dio = Dio(); // 使用默认配置
    _dio.interceptors.add(_headerInterceptors);

    if (showLoading) {
      _dio.interceptors.add(_loadingInterceptors);
    } else {
      _dio.interceptors.remove(_loadingInterceptors);
    }

    if (showErrorToast) {
      _dio.interceptors.add(_errorInterceptors);
    } else {
      _dio.interceptors.remove(_errorInterceptors);
    }

    if (Env.isTest()) {
      _dio.interceptors.add(LogsInterceptors());
    }

    return _dio;
  }

  ///获取响应对象
  Object getResponseObject(Response response, bool dealResponse) {
    if (dealResponse) {
      return response.data;
    } else {
      return response;
    }
  }

  Future get<T>(
    String url,
    Map<String, dynamic>? params, {
    bool showLoading = true,
    bool dealResponse = true,
    bool showErrorToast = true,
    CancelToken? cancelToken,
    Options? options,
  }) async {
    var _dio = getDio(showLoading, showErrorToast);
    var response;
    if (params != null) {
      response = await _dio.get(url,
          queryParameters: params, cancelToken: cancelToken, options: options);
    } else {
      response = await _dio.get(url, cancelToken: cancelToken);
    }

    return getResponseObject(response, dealResponse);
  }

  Future put<T>(
    String url,
    Map<String, dynamic>? params, {
    bool showLoading = true,
    bool dealResponse = true,
    bool showErrorToast = true,
    CancelToken? cancelToken,
  }) async {
    var _dio = getDio(showLoading, showErrorToast);
    var response;

    if (params != null) {
      LogUtil.get().d('请求参数: ' + params.toString());
      response = await _dio.put(url,
          queryParameters: params, cancelToken: cancelToken);
    } else {
      response = await _dio.put(url, cancelToken: cancelToken);
    }

    return getResponseObject(response, dealResponse);
  }

  /// 类似同步请求，直接获取response,由调用者自己处理异常情况，如空指针
  /// 通过Future.then()获取返回内容, 并通过Future.catchError处理异常情况
  /// [showLoading] 是否显示加载弹窗，
  /// [showErrorToast] 是否显示网络错误提示
  /// [dealResponse] 是否直接返回处理后的数据，[ture]返回[response.data],[false]返回[response]
  /// [cancelToken] 取消请求
  Future postForm(String url, Map<String, dynamic> params,
      {bool showLoading = true,
      bool dealResponse = false,
      bool showErrorToast = true,
      Options? options,
      CancelToken? cancelToken,
      String description = ''}) async {
    var _dio = getDio(showLoading, showErrorToast);

    var formData = FormData.fromMap(params);
    var response = await _dio.post(url,
        data: formData, cancelToken: cancelToken, options: options);
    return getResponseObject(response, dealResponse);
  }

  /// 类似同步请求，直接获取response,由调用者自己处理异常情况，如空指针
  /// 通过Future.then()获取返回内容, 并通过Future.catchError处理异常情况
  /// [showLoading] 是否显示加载弹窗，
  /// [showErrorToast] 是否显示网络错误提示
  /// [dealResponse] 是否直接返回处理后的数据，[ture]返回[response.data],[false]返回[response]
  /// [cancelToken] 取消请求
  /// [description] 接口描述
  Future post(String url, Map<String, dynamic> params,
      {bool showLoading = true,
      bool dealResponse = false,
      bool showErrorToast = true,
      CancelToken? cancelToken,
      Options? options,
      String description = ''}) async {
    var _dio = getDio(showLoading, showErrorToast);

    ///此处方法应作为方法入参
    var response = await _dio.post(url,
        data: params, cancelToken: cancelToken, options: options);

    return getResponseObject(response, dealResponse);
  }

  Future postNoparams(
    String url, {
    bool showLoading = true,
    bool dealResponse = false,
    bool showErrorToast = true,
    Options? options,
    CancelToken? cancelToken,
  }) async {
    var _dio = getDio(showLoading, showErrorToast);
    var response =
        await _dio.post(url, options: options, cancelToken: cancelToken);
    return getResponseObject(response, dealResponse);
  }
}

class LoadingInterceptors extends InterceptorsWrapper {
  @override
  Future<void> onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    showLoading('网络请求中');

    return handler.next(options);
  }

  @override
  Future onResponse(
      Response response, ResponseInterceptorHandler handler) async {
    closeLoading();
    return handler.next(response);
  }

  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    LogUtil.get().e(err);
    closeLoading();
  }
}

///请求头信息
class HeaderInterceptors extends InterceptorsWrapper {
  @override
  Future onRequest(
      RequestOptions options, RequestInterceptorHandler handler) async {
    options.headers['accept-language'] = 'zh-cn';
    options.headers['content_type'] = 'json';
    options.baseUrl =
        Env.isTest() ? 'https://restapi.amap.com' : 'https://restapi.amap.com/';

    ///超时
    options.connectTimeout = Duration(milliseconds: 300000);
    options.sendTimeout = Duration(milliseconds: 300000);
    options.receiveTimeout = Duration(milliseconds: 300000);
    return handler.next(options);
  }
}

class LogsInterceptors extends InterceptorsWrapper {
  @override
  Future onRequest(RequestOptions options, handler) async {
    LogUtil.get().d(
        '请求链接Url：${options.baseUrl + options.path}\n请求参数：${options.queryParameters.toString()}\n');
    if (options.headers.isNotEmpty) {
      LogUtil.get().d(
          '请求头域信息: ${options.headers.toString()}\n请求base url：${options.baseUrl}');
    }
    return handler.next(options);
  }

  @override
  Future onResponse(Response response, handler) async {
    LogUtil.get().d(
        '请求Url:${response.requestOptions.baseUrl + response.requestOptions.path}\n返回参数: ' +
            response.toString());

    return handler.next(response); // continue
  }

  @override
  Future onError(DioError err, handler) async {
    LogUtil.get().d(
        '请求异常: + ${err.toString()}\n请求异常信息:${err.response?.toString() ?? ''}\n请求地址信息: ${err.response?.requestOptions.uri.toString()}');
    handler.next(err);
  }
}

/// 401 无权限
class LoginInterceptors extends InterceptorsWrapper {
  @override
  Future onError(DioError error, handler) async {
    if (error.response != null && 401 == error.response?.statusCode) {
      await Alert('用户账号已失效,请重新登录');
      // UserAccountService.logout();
      await RouterUtil.navigatorKey.currentState?.pushNamed(MAIN);
    }
    ;
  }
}

class ErrorInterceptors extends InterceptorsWrapper {
  @override
  Future onError(DioError err, ErrorInterceptorHandler handler) async {
    if ((err.response != null && 401 == err.response?.statusCode) ||
        err.type == DioErrorType.cancel) {
      return;
    }
    switch (err.type) {
      /// 请求超时
      case DioErrorType.receiveTimeout:
        await Alert('connectTimeout');
        break;
      case DioErrorType.connectionTimeout:
        await Alert('receiveTimeout');
        break;
      case DioErrorType.sendTimeout:
        await Alert('网络超时，请稍候再试');
        break;
      case DioErrorType.unknown:
        await Alert('请检查域名是否正确');
        break;
      default:
        await Alert('网络错误，请稍候再试(${err.response?.statusCode ?? 'ERROR'})');
        break;
    }
    handler.next(err);
  }
}

final NetUtils netUtils = NetUtils();
